﻿package org.dm.net 
{
	import flash.events.EventDispatcher;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.net.URLRequest;
	import org.dm.events.NetEvent;
	import org.dm.events.ApplicationEvent;
	
	import flash.utils.Timer;
	import flash.display.Loader;
	import flash.system.LoaderContext;
	import flash.system.ApplicationDomain;
	
	/**
	 * ...
	 * @author Scott
	 */
	public class DLoader extends EventDispatcher implements IBaseNet
	{
		public static const TARGET_CHILD : String = "child";
        public static const TARGET_SAME : String = "same";
        public static const TARGET_NEW : String = "new";
		
		public static const DEF_MAX_RET_TIMES:int = 3;
		public static const DEF_MAX_TIMEOUT:int = 3000;
		
		private var _regetTimes:int = 0;
		private var _maxRetryTimes:int = 0;
		private var _Timer:Timer = null;
		private var _loader:Loader;
		private var _loaderContext:LoaderContext;
		private var _url:URLRequest;
		
		public function DLoader() 
		{
			super();
			_loader = new Loader();
			_loaderContext = new LoaderContext();
		}
		
		private function add():void
		{
			if(_Timer!=null)
			{
				_Timer.addEventListener(TimerEvent.TIMER,OnOutTime);
			}
			
			_loader.contentLoaderInfo.addEventListener(Event.COMPLETE,OnDownOk);
			_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,OnIOError);
        	_loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,OnSecurityError);
        	_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,OnProgress);
		}
		
		private function remove():void
		{
			if(_Timer!=null)
			{
				_Timer.removeEventListener(TimerEvent.TIMER, OnOutTime);
			}
			
			_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,OnDownOk);
			_loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,OnIOError);
        	_loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,OnSecurityError);
        	_loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS,OnProgress);
		}
		
		public function request(url:String, target:String = TARGET_CHILD,retry:int = DEF_MAX_RET_TIMES,timeout:int = -1):void
		{
			_regetTimes = 0;
			_maxRetryTimes = retry;
			
			_url = NetMgr.getURLStr(url);
			
			if(timeout>0)
			{
				_Timer = new Timer(timeout);
			}
			
			switch(target)
            {
				case TARGET_CHILD :
					_loaderContext.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
				break;
				case TARGET_SAME :
					_loaderContext.applicationDomain = ApplicationDomain.currentDomain;
				break;
				case TARGET_NEW :
					_loaderContext.applicationDomain = new ApplicationDomain();
				break;
            }
			
			add();
			Try();
		}
		
		private function Try():void
		{
			_loader.load(_url,_loaderContext);
			
			if(_Timer!=null)
			{
				_Timer.reset();
				_Timer.start();
			}
			
		}
		
		private function Retry():void
		{
			if(_regetTimes++<_maxRetryTimes)
			{
				Try();
			}
			else
			{
				remove();
				dispatchEvent(new IOErrorEvent(IOErrorEvent.NETWORK_ERROR));
			}
		}
		
		private function OnIOError(e:IOErrorEvent):void
		{
			Retry();
		}
		
		private function OnSecurityError(e:SecurityErrorEvent):void
		{
			Retry();
		}
		
		private function OnOutTime(e:TimerEvent):void
		{
			Retry();
		}
		
		private function OnProgress(e:ProgressEvent):void
		{
			_regetTimes = 0;
			
			if(_Timer!=null)
			{
				_Timer.reset();
				_Timer.start();
			}
			
			dispatchEvent(e);
		}
		
		private function OnDownOk(e:Event):void
		{		
			remove();
			this.dispatchEvent(new NetEvent(NetEvent.LOAD_COMPLETE, e.target));
			//_loader.contentLoaderInfo.sharedEvents.addEventListener(ApplicationEvent.DOMAIN_DEFINE,getDomain);
		}
		private function getDomain(event:Event):void
		{
			trace(String((Object(event).defineClass)));
		}
	}

}